#include "teacup.h"
#include "tea.h"

static bool decode_nible(const unsigned char _in, unsigned char &_out)
{
	if ((_in >= 0x30) && (_in <= 0x39))
	{
		_out = _in - 0x30;
		return true;
	}
	else if ((_in >= 0x41) && (_in <= 0x46))
	{
		_out = _in - 0x41 + 10;
		return true;
	}
	else if ((_in >= 0x61) && (_in <= 0x66))
	{
		_out = _in - 0x61 + 10;
		return true;
	}
	
	return false;
}

static bool decode_byte(const unsigned char _in[2], unsigned char &_out)
{
	unsigned char lo;
	unsigned char hi;
	
	if (decode_nible(_in[0], hi) && decode_nible(_in[1], lo))
	{
		_out = hi << 4 | lo;
		return true;
	}
	else
	{
		return false;
	}
}

static bool decode_word(const unsigned char in[4], unsigned char out[2])
{
	return  (
				decode_byte(in, out[0]) && 
				decode_byte(in+2, out[1])
			);
}

bool teacup::load_key( const std::string &_txt_key )
{
	tea_key_t key;
	unsigned char bc = 0;
	
	for(const char *p = _txt_key.c_str(); (*p != '\0') || (bc < 8) ;)
	{
		if (*p == '-')
		{
			p++;
			continue;
		}
		
		if (!decode_word((const unsigned char*)p, key + (bc * 2) ) )
			return false;
		
		bc ++; 
		
		p += 4;
	}
	
	if (bc == 8)
	{
		memmove(key_, key, sizeof(key_));
		return true;
	}	
	else
		return false;
}

bool teacup::decode( unsigned char *_buffer, size_t _size )
{
	if (((_size % tea_buf_align) != 0) || (_size < 8))
		return false;

	for(unsigned int i = 0 ; i < _size; i += 8)
	{
		tea_decrypt((uint32_t*)(_buffer + i), (uint32_t*)key_);
	}

	return true;
}

bool teacup::encode( unsigned char *_buffer, size_t _size )
{
	if (((_size % tea_buf_align) != 0) || (_size < 8))
		return false;

	for(unsigned int i = 0 ; i < _size; i += 8)
	{
		tea_encrypt((uint32_t*)(_buffer + i), (uint32_t*)key_);
	}

	return true;
}
